iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Modern Web

重寫一套比我還老的系統:21 歲的校園文字廣播系統系列 第 8 篇

Day 8|這我會,登入就用 JW……先別急,來口餅乾再說。

  • 分享至 

  • xImage
  •  

ORM 也建了,異步的問題也解答了,是時候來寫個登入了。

歐?說到登入那必會有登入狀態的實作。

那新系統當然要用 JWT 啦!

就知道你會這麼講,畢竟我也曾是你。
但事實上 Session 跟 JWT 各有優缺點,要按照使用場景選擇歐。

我知道嘛,Session 簡單,JWT 複雜。

Session 沒有 cookie,JWT 要維護兩個 cookie 嘛。

嗯,似乎是這樣?

但說實話,用慣了 JWT,平時都直接上 JWT,沒試過 session。
那今天就來研究這兩種登入狀態的原理吧。

先從我們熟悉的 JWT 開始吧,你來講,我順便查查 session 的資料。

什麼是 JWT?

JWT 的全名是 JSON Web Token,特點是能在 token 本身攜帶資料。

目前沒說錯。

Token 上面通常會帶有身分、時效等資訊,最後還會附上一段簽名。

沒錯,這個簽名可以說是整個 JWT 的精隨,這邊你得展開一下。

這個簽名的作用是:讓伺服器確認 Token 的內容有沒有被修改過。

比如今天 Token 裡面寫著:

{
    "user_id": 114514,
    "role": "student"
}

如果我偷偷把 student 改成 admin 呢?

噗嘰啪(簽名對不上的聲音)

因為你沒有伺服器的金鑰,沒辦法替修改後的內容產生合法的簽名。

所以 JWT 的內容不能改?

可以改,但改了會被發現(如果伺服器驗證實作沒問題的話)。

而這也帶出了 JWT 很重要的一個特性:伺服器收到 Token 後,可以直接驗證它的簽名、有效期限等資訊,而不一定需要另外保存一份登入狀態。

這就是我們常說的 Stateless(無狀態)。

那這樣不是很好嗎?伺服器連登入狀態都不用存。

是很方便,但有個問題。

這張 Token 要多久過期?

如果設成 15 分鐘:

那我每 15 分鐘就要重新登入一次?

對。

那誰要用?

所以我們通常不會讓使用者真的每 15 分鐘重新登入。

這時候就會出現第二張 Token:

Refresh Token。

原本那張負責存取 API 的 Token,我們稱作 Access Token;在這裡,它就是前面提到的 JWT,有效期限可以設得比較短。

Access Token 過期後,前端就拿著有效期限更長的 Refresh Token 去找伺服器:

老闆,昏睡紅茶再來一杯。

伺服器確認 Refresh Token 有效後,再發一張新的 Access Token。

如此一來,使用者甚至不會發現自己的 Access Token 曾經過期。

這就是我們常說的無感刷新。

好,那 JWT 解決了。
Session 呢?

Session 啊……

我剛剛查資料的時候發現一件很有趣的事情。

什麼?

你還記得你剛剛說什麼嗎?

Session 簡單,JWT 複雜?

下一句。

Session 沒有 cookie,JWT 要維護兩個 cookie?

對,就是這句。

怎樣,我說錯了?

你一次錯了兩個。

什麼是 Session?

Session,直翻中文就是——會話。

蛤?那不是 Conversation 嗎?

不是那個會話。

這裡的 Session,指的是使用者和伺服器之間的一段「會話」。

比如你登入系統之後,伺服器需要記得:

「喔,這個人剛剛登入過,他是蘇同學。」

直到你登出,或者這段 Session 過期為止。

所以跟 JWT 一樣,都是拿來記住我是誰?

目的差不多,但做法正好不太一樣。

JWT 是把身分資訊放進 Token 裡,再透過簽名讓伺服器驗證。

Session 則是把登入狀態留在伺服器上。

那瀏覽器怎麼跟伺服器說「我是剛才那個人」?

問得好。

這時候,我們就需要一個 Session ID。

假設今天你成功登入,伺服器建立了一個 Session:

Session ID: abc123
User: 蘇同學

接著把 abc123 交給瀏覽器。

之後瀏覽器每次發出請求時,都把這個 Session ID 帶回來。

伺服器一看:

abc123 → 蘇同學

喔,是你啊。

等等,所以瀏覽器還是要存一個東西?

那這個 Session ID 要放哪?

Cookie。

……

超好笑,剛剛是不是有人說 Session 沒有 Cookie?
是誰啊,好難猜啊。

不知道欸,好難猜啊。

實際上,Session 很常見的做法,就是把 Session ID 放進 Cookie。

所以你前面說:

Session 沒有 cookie,JWT 要維護兩個 cookie 嘛。

前半句就已經死了。

至於後半句……

我們等等再處理。


那現在 Session 的基本流程就很清楚了。

使用者登入後:

登入
 ↓
伺服器建立 Session
 ↓
Session ID 放進 Cookie
 ↓
瀏覽器之後自動帶上 Cookie
 ↓
伺服器用 Session ID 找回登入狀態

好,那 Session 也會過期吧?

不然我登入一次豈不是可以用到畢業?

當然會。

但這裡就出現 Session 跟剛才 JWT 很有趣的一個差別了。

還記得 JWT 怎麼續命嗎?

Access Token 過期之後,用 Refresh Token 換一張新的。

沒錯。

但 Session 的登入狀態本來就在伺服器手上。

所以當使用者持續操作網站時,伺服器可以直接更新這個 Session 的過期時間。

例如我們規定:

30 分鐘沒有操作,就讓 Session 過期。

你在 10:00 登入,那 Session 原本會在 10:30 過期。

但你 10:20 又操作了一次網站。

伺服器就可以把過期時間往後延:

10:00 登入 → 10:30 過期
10:20 操作 → 10:50 過期
10:40 操作 → 11:10 過期

在這種設計下,只要你持續使用,就不會莫名其妙被踢出去。

但如果你真的離開超過 30 分鐘——

噗嘰啪(Session 過期的聲音)

等等。

所以 Session 根本不需要 Refresh Token?

答對囉。

……那 JWT 也不一定要兩個 Cookie 是?

超好笑,後半句也錯了。

誰規定 JWT 一定要 Refresh 了?

如果使用情境允許,只有一張 Access Token,用到過期再重新登入,也完全可以。

而且就算真的用了 Access Token + Refresh Token,也不代表它們兩個都一定得放進 Cookie。

所以 JWT、Session 跟 Cookie 其實是三件不同的東西?

對。

JWT 和 Session 在回答「登入狀態怎麼處理」。

Cookie 在回答「瀏覽器怎麼保存、攜帶資料」。

只是這幾個東西實在太常一起出現,所以很容易被我……我是說,被你混在一起。

超好笑。

總之,現在兩邊的原理都搞懂了。

問題就剩下一個:

我們到底該選哪個?

JWT 還是 Session?

所以,現在可以選了嗎?

其實還不行。

蛤?不是都講完了?

因為我們到現在只搞懂了「登入狀態怎麼維持」,還有一個很重要的東西沒處理。

不管最後選 JWT 還是 Session,我們都有可能把東西放進 Cookie。

那問題來了:

這顆 Cookie 安全嗎?

如果裡面的東西被偷走,別人是不是就能拿著它冒充你?

……好像是欸。

所以在決定 JWT 還是 Session 之前,我想先把 Cookie 這件事處理掉。

包括怎麼避免 JavaScript 直接讀取它、什麼情況下瀏覽器會把 Cookie 帶出去,以及跨站請求又會帶來什麼問題。

至於最後會選哪一個……

先劇透吧。

我們會選 Session。

但為什麼?

明天處理完 Cookie,我們再回來回答這個問題。

總之,來口餅乾再說(嚼)。


上一篇
Day 7|都是五秒,Async 到底快在哪裡?
下一篇
Day 9|我去,不早說,cookie 被盜原來這麼簡單
系列文
重寫一套比我還老的系統:21 歲的校園文字廣播系統 共 20 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言